package com.reebake.ideal.security.oauth2.config;

import com.reebake.ideal.security.oauth2.client.*;
import com.reebake.ideal.security.oauth2.properties.OAuth2ClientSecurityProperties;
import com.reebake.ideal.security.service.UserSecurityService;
import com.reebake.ideal.servlet.core.ResponseBodyWrapper;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.ApplicationEventPublisher;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.security.config.Customizer;
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.oauth2.client.registration.ClientRegistrationRepository;
import org.springframework.security.oauth2.client.web.DefaultOAuth2AuthorizationRequestResolver;
import org.springframework.security.oauth2.client.web.OAuth2AuthorizationRequestRedirectFilter;
import org.springframework.security.web.SecurityFilterChain;
import org.springframework.security.web.authentication.AuthenticationSuccessHandler;

@Configuration
@Slf4j
public class Oauth2ClientConfig {
	@Autowired
	private OAuth2ClientSecurityProperties oAuth2ClientSecurityProperties;
	@Autowired
	private ClientRegistrationRepository clientRegistrationRepository;
	@Autowired
	private JustAuthFactory justAuthFactory;
	@Autowired
    private UserSecurityService userSecurityService;
	@Autowired
	private OAuth2BindUserRepository oAuth2BindUserRepository;
	@Autowired
	private ResponseBodyWrapper responseBodyWrapper;
    @Autowired
    private ApplicationEventPublisher applicationEventPublisher;

	@Bean
	SecurityFilterChain oauth2ClientSecurityFilterChain(HttpSecurity http) throws Exception {
		log.info("启动SecurityFilterChain: oauth2-client");
		DefaultOAuth2AuthorizationRequestResolver oauth2AuthorizationRequestResolver = getOauth2AuthorizationRequestResolver();
		http.securityMatcher("/oauth2/authorization/**", "/login/oauth2/code/**", "/oauth2/client-registration/all", "/oauth2/client-registration/bind")
				.authorizeHttpRequests(authorizeRequest -> authorizeRequest.requestMatchers("/oauth2/authorization/**", "/login/oauth2/code/**", "/oauth2/client-registration/all", "/oauth2/client-registration/bind").permitAll().anyRequest().authenticated())
				.oauth2Login(oauth2Login -> oauth2Login.loginPage(oAuth2ClientSecurityProperties.getLoginFormUrl())
						.authorizationEndpoint(authorizationEndpoint ->
								authorizationEndpoint.authorizationRequestResolver(oauth2AuthorizationRequestResolver)
                                        .authorizationRedirectStrategy(new SmartOauth2RedirectStrategy(responseBodyWrapper))
                                        .authorizationRequestRepository(new DefaultOAuth2AuthorizationRequestRepository()))
						.tokenEndpoint(tokenEndpoint -> tokenEndpoint.accessTokenResponseClient(new SmartOAuth2AccessTokenResponseClient(justAuthFactory)))
						.userInfoEndpoint(userInfoEndpoint -> userInfoEndpoint.userService(new SmartOauth2UserService()))
						.successHandler(authenticationSuccessHandler())
				);
		http.csrf(csrf -> csrf.disable());
        http.cors(Customizer.withDefaults());
		return http.build();
	}

	private DefaultOAuth2AuthorizationRequestResolver getOauth2AuthorizationRequestResolver() {
		DefaultOAuth2AuthorizationRequestResolver oauth2AuthorizationRequestResolver = new DefaultOAuth2AuthorizationRequestResolver(clientRegistrationRepository, OAuth2AuthorizationRequestRedirectFilter.DEFAULT_AUTHORIZATION_REQUEST_BASE_URI);
		SmartOauth2AuthorizationRequestCustomizer smartOauth2AuthorizationRequestCustomizer = new SmartOauth2AuthorizationRequestCustomizer(clientRegistrationRepository, justAuthFactory);
		oauth2AuthorizationRequestResolver.setAuthorizationRequestCustomizer(smartOauth2AuthorizationRequestCustomizer);
		return oauth2AuthorizationRequestResolver;
	}

	private AuthenticationSuccessHandler authenticationSuccessHandler() {
        SmartOAuth2AuthenticationSuccessHandler smartOAuth2AuthenticationSuccessHandler = new SmartOAuth2AuthenticationSuccessHandler(responseBodyWrapper, userSecurityService, oAuth2BindUserRepository, oAuth2ClientSecurityProperties, applicationEventPublisher);
		smartOAuth2AuthenticationSuccessHandler.setTargetUrlParameter(oAuth2ClientSecurityProperties.getTargetUrlParameter());
		return smartOAuth2AuthenticationSuccessHandler;
	}

}
